package org.wso2.carbon.identity.entitlement.axis2handler;

import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axis2.AxisFault;
import org.apache.axis2.handlers.AbstractHandler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.StringReader;


/**
 * Created by IntelliJ IDEA.
 * User: pushpalanka
 * Date: 5/5/11
 * Time: 2:14 PM
 * To change this template use File | Settings | File Templates.
 */
public class EntitlementHandler extends AbstractHandler {




    private static final Log log = LogFactory.getLog(EntitlementHandler.class);

    private boolean remote = true;
    private String remoteServiceUserName;
    private String remoteServicePassword;
    private String remoteServiceUrl;


    public final static String DEFAULT_CLIENT_REPO = "/home/pushpalanka/Installations/apache-tomcat-7.0.11/webapps/axis2/WEB-INF";
    public final static String DEFAULT_AXIS2_XML = "/home/pushpalanka/Installations/apache-tomcat-7.0.11/webapps/axis2/WEB-INF/conf/axis2.xml";
    private String requestString;

    public String requestGuideName = "org.wso2.carbon.identity.samples.RequestEntranceToIS.RequestEvaluatingClient";
    private String decision;





    public InvocationResponse invoke(org.apache.axis2.context.MessageContext messageContext) throws AxisFault {


        String userName = null;
        String serviceName = null;
        String action = null;
        EntitlementCallbackReader callback = null;
        String resourceName = null;
        String[] env = null;



        System.out.println(messageContext.getAxisService());

        System.out.println("Message Context: "+messageContext);


        if (log.isDebugEnabled()) {
            log.debug("Handling for Entitlement started");
        }

        callback = new UTEntitlementCallbackReader();





        System.out.println(callback.findServiceName(messageContext));
        System.out.println("Username:"+callback.getUserName(messageContext));
        userName = callback.getUserName(messageContext);
        serviceName = callback.findServiceName(messageContext);

        action = callback.findAction(messageContext);
        env = callback.findEnvironment(messageContext);



        if (userName == null) {
            log.error("User name not provided for the Entitlement axis2handler - can't proceed");

        }




        resourceName = serviceName;





        OMElement requestOM = createXACMLrequestElement(userName, resourceName,action,env);
        requestString = requestOM.toString();
        System.out.println(requestString);
        RequestEvaluatingClient requestEvaluatingClient = new RequestEvaluatingClient();
        decision = requestEvaluatingClient.sendRequest(requestString);
        String response = readResponse(decision);





        if ("Permit".equals(response.trim())) {
            return InvocationResponse.CONTINUE;
        } else {
            if (log.isDebugEnabled()) {
                log.debug("User not authorized to perform the action :" + decision);
            }
        }


        throw new AxisFault("User not authorized to perform the action");
    }






    /*
    Create the XACML request using the extracted values
     */
    private OMElement createXACMLrequestElement(String userName, String resourceName, String action, String[] env){
        OMFactory factory = OMAbstractFactory.getOMFactory();

        // lets create the namespace object of the Request element
        OMNamespace ons1 = factory.createOMNamespace(EntitlementHandlerConstants.REQ_RES_CONTEXT,null);
        OMNamespace ons2 = factory.createOMNamespace(EntitlementHandlerConstants.REQ_SCHEME , "xsi");

        // now create the Article element with the above namespace
        OMElement requestElement = factory.createOMElement(EntitlementHandlerConstants.REQUEST_ELEMENT,null );

        requestElement.setNamespace(ons2);
        requestElement.setNamespace(ons1);

        OMElement subjects = factory.createOMElement(EntitlementHandlerConstants.SUBJECT_ELEMENT , null);
        OMElement resource = factory.createOMElement(EntitlementHandlerConstants.RESOURCE_ELEMENT , null);
        OMElement actionOm = factory.createOMElement(EntitlementHandlerConstants.ACTION_ELEMENT, null);



        if(userName!=null && !userName.equals("")){
            XACMLElementBuilder XACMLElementBuilder = new XACMLElementBuilder();
            OMElement subjectSub = XACMLElementBuilder.createAttribute(EntitlementHandlerConstants.SUBJECT_ID_DEFAULT, EntitlementHandlerConstants.STRING_DATA_TYPE, userName , null);
            subjects.addChild(subjectSub);
            requestElement.addChild(subjects);
        }

        if(resourceName!=null && !resourceName.equals("")){
            XACMLElementBuilder XACMLElementBuilder = new XACMLElementBuilder();
            OMElement resourceSub = XACMLElementBuilder.createAttribute(EntitlementHandlerConstants.RESOURCE_ID,EntitlementHandlerConstants.STRING_DATA_TYPE, resourceName,null);
            resource.addChild(resourceSub);
            requestElement.addChild(resource);
        }

        if(action!=null && !action.equals("")){
            XACMLElementBuilder XACMLElementBuilder = new XACMLElementBuilder();
            OMElement actionSub = XACMLElementBuilder.createAttribute(EntitlementHandlerConstants.ACTION_ID, EntitlementHandlerConstants.STRING_DATA_TYPE,action,null);
            actionOm.addChild(actionSub);
            requestElement.addChild(actionOm);
        }


        return requestElement;
    }


    /*
    Extract just the relevant response from the received message whether "Permit","Deny" .. etc.
     */
    public String readResponse(String res){


        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();


        // create an input source for target document and parse it
        InputSource is = new InputSource( new StringReader( res )  );
        Document document = null;


        try {
            try {
                document =factory.newDocumentBuilder().parse(is);
            } catch (ParserConfigurationException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        } catch (SAXException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (IOException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }


        String response = document.getFirstChild().getTextContent();

        System.out.println( "Decision value = " + response );


        return response.trim();

    }


    public boolean isRemote() {
        return remote;
    }

    public void setRemote(boolean remote) {
        this.remote = remote;
    }

    public String getRemoteServiceUserName() {
        return remoteServiceUserName;
    }

    public void setRemoteServiceUserName(String remoteServiceUserName) {
        this.remoteServiceUserName = remoteServiceUserName;
    }

    public String getRemoteServicePassword() {
        return remoteServicePassword;
    }

    public void setRemoteServicePassword(String remoteServicePassword) {
        this.remoteServicePassword = remoteServicePassword;
    }

    public String getRemoteServiceUrl() {
        return remoteServiceUrl;
    }

    public void setRemoteServiceUrl(String remoteServiceUrl) {
        this.remoteServiceUrl = remoteServiceUrl;
    }


}


